﻿// ---------------------------------------------------------------------------------------------------------------------
//   Copyright (c) SRT Solutions 2009. All rights reserved.
// ---------------------------------------------------------------------------------------------------------------------

namespace SRTSolutions.Elevate.PatternMatching
{
    using global::System;

    /// <summary>
    /// Contains extension methods on pattern matching.
    /// </summary>
    public static class PatternMatchExtensions
    {
        /// <summary>
        /// Defines a match that equality compares a value.
        /// </summary>
        /// <typeparam name="T">The type being matched against.</typeparam>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="context">The context.</param>
        /// <param name="value">The value to equality compare.</param>
        /// <param name="result">A function to evaluate to get the result.</param>
        /// <returns>The pattern match object for this type, context, and result.</returns>
        public static PatternMatch<T, TResult> With<T, TResult>(this PatternMatchContext<T> context, T value, Func<T, TResult> result)
        {
            if (result == null)
                throw new ArgumentNullException("result", "result is null.");

            var match = new PatternMatch<T, TResult>(context.value);
            return match.With(input => value.Equals(input), result);
        }

        /// <summary>
        /// Defines a match that equality compares a value.
        /// </summary>
        /// <typeparam name="T">The type being matched against.</typeparam>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="context">The context.</param>
        /// <param name="value">The value to equality compare.</param>
        /// <param name="result">The result value.</param>
        /// <returns>The pattern match object for this type, context, and result.</returns>
        public static PatternMatch<T, TResult> With<T, TResult>(this PatternMatchContext<T> context, T value, TResult result)
        {
            var match = new PatternMatch<T, TResult>(context.value);
            return match.With(input => value.Equals(input), ingnore => result);
        }

        /// <summary>
        /// Defines a match that equality compares a value.
        /// </summary>
        /// <typeparam name="T">The type being matched against.</typeparam>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="match">The match.</param>
        /// <param name="value">The value to equality compare.</param>
        /// <param name="result">A function to evaluate to get the result.</param>
        /// <returns>The pattern match object for this type, context, and result</returns>
        public static PatternMatch<T, TResult> With<T, TResult>(this PatternMatch<T, TResult> match, T value, Func<T, TResult> result)
        {
            return match.With(input => value.Equals(input), result);
        }

        /// <summary>
        /// Defines a match that equality compares a value.
        /// </summary>
        /// <typeparam name="T">The type being matched against.</typeparam>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="match">The match.</param>
        /// <param name="value">The value to equality compare.</param>
        /// <param name="result">The result value.</param>
        /// <returns></returns>
        public static PatternMatch<T, TResult> With<T, TResult>(this PatternMatch<T, TResult> match, T value, TResult result)
        {
            return match.With(input => value.Equals(input), ignore => result);
        }

        /// <summary>
        /// Defines an else condition that uses a concrete value instead of a function.
        /// </summary>
        /// <typeparam name="T">The type being matched against.</typeparam>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="match">The match.</param>
        /// <param name="value">The value to return.</param>
        /// <returns>The pattern match object for this type, context, and result</returns>
        public static PatternMatch<T, TResult> Else<T, TResult>(this PatternMatch<T, TResult> match, TResult value)
        {
            return match.Else(input => value);
        }
    }
}
